#pragma once

#include <memory>
#include <functional>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include "Socket.hpp"
#include "InetAddr.hpp"

using callback_t = std::function<std::string(std::string&)>;

// TcpServer: 只进行IO
class TcpServer
{
public:
    TcpServer(int port, callback_t cb)
        : _port(port),
          _cb(cb),
          _listensocket(std::make_unique<TcpSocket>())
    {
        _listensocket->BuildLisentSocketMethod(_port); // 创建监听套接字
    }

    void HandlerRequest(std::shared_ptr<Socket> sockfd, InetAddr addr)
    {
        // 长服务
        std::string inbuffer; // 字节流队列
        while (true)
        {
            ssize_t n = sockfd->Recv(&inbuffer); // 进行读
            if (n > 0)
            {
                LOG(LogLevel::DEBUG) << addr.ToString() << "# " << inbuffer;
                std::string send_str = _cb(inbuffer);
                if (send_str.empty())
                {
                    continue;
                }
                sockfd->Send(send_str);// 进行写
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << addr.ToString() << "quit, me too";
                break;
            }
            else
            {
                LOG(LogLevel::DEBUG) << addr.ToString() << "read error, quit";
                break;
            }
        }
        sockfd->Close();
    }

    void Run()
    {
        signal(SIGCHLD, SIG_IGN); // 使用信号来解决等待子进程问题
        while (true)
        {
            InetAddr addr;
            auto sockfd = _listensocket->Accept(&addr);
            if (sockfd == nullptr)
            {
                continue;
            }
            LOG(LogLevel::DEBUG) << "获得一个新连接: " << addr.ToString() << ", sockfd: " << sockfd->GetSocket();
            if (fork() == 0) // 子进程
            {
                // 子进程关闭监听套接字, 不影响父进程使用监听套接字
                _listensocket->Close();
                // 执行对应请求
                HandlerRequest(sockfd, addr);
                exit(0);
            }
            sockfd->Close(); // 父进程关闭普通套接字
        }
    }
    ~TcpServer() {}

private:
    int _port;
    std::unique_ptr<Socket> _listensocket;
    callback_t _cb;
};